/**
 * The MIT License (MIT)
 *
 * Copyright (c) 2021 Marcus Britanicus (https://gitlab.com/marcusbritanicus)
 * Copyright (c) 2021 Abrar (https://gitlab.com/s96Abrar)
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all
 * copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE.
 **/

#pragma once

#include <QObject>
#include <QRect>

struct wl_seat;
struct wl_array;
struct wl_output;
struct wl_surface;
struct zwlr_foreign_toplevel_handle_v1;
struct zwlr_foreign_toplevel_handle_v1_listener;
struct zwlr_foreign_toplevel_manager_v1;
struct zwlr_foreign_toplevel_manager_v1_listener;

namespace WQt {
    class WindowManager;
    class WindowHandle;
    typedef QList<WindowHandle *> WindowHandles;
}

class WQt::WindowManager : public QObject {
    Q_OBJECT;

    public:
        WindowManager( zwlr_foreign_toplevel_manager_v1 *winMgr );
        ~WindowManager();

        void setup();

        zwlr_foreign_toplevel_manager_v1 *get();

        WQt::WindowHandles windowHandles();

    private:

        /**
         * Get the handle, and send out a signal.
         */
        static void handleTopLevelAdded( void *, zwlr_foreign_toplevel_manager_v1 *, zwlr_foreign_toplevel_handle_v1 * );
        static void handleFinished( void *, zwlr_foreign_toplevel_manager_v1 * );

        static const zwlr_foreign_toplevel_manager_v1_listener mWindowMgrListener;

        zwlr_foreign_toplevel_manager_v1 *mObj;
        WQt::WindowHandles mTopLevels;

        bool mIsSetup = false;

    Q_SIGNALS:

        /**
         * Get the handle
         */
        void newTopLevelHandle( WQt::WindowHandle *handle );
        void finished();
};

class WQt::WindowHandle : public QObject {
    Q_OBJECT;

    public:
        WindowHandle( zwlr_foreign_toplevel_handle_v1 *handle );
        ~WindowHandle();

        void setup();

        QString appId() const;
        QString title() const;

        bool isActivated();
        void activate( wl_seat *seat );

        bool isMaximized();
        void setMaximized();
        void unsetMaximized();

        bool isMinimized();
        void setMinimized();
        void unsetMinimized();

        bool isFullScreen();
        void setFullScreen( wl_output *op = nullptr );
        void unsetFullScreen();

        void setMinimizeRect( wl_surface *, QRect );

        void close();

        zwlr_foreign_toplevel_handle_v1 *get();

    private:
        static void handleTitle( void *data, zwlr_foreign_toplevel_handle_v1 *hndl, const char *title );
        static void handleAppId( void *data, zwlr_foreign_toplevel_handle_v1 *hndl, const char *app_id );
        static void handleOutputEnter( void *data, zwlr_foreign_toplevel_handle_v1 *hndl, wl_output *wlOut );
        static void handleOutputLeave( void *data, zwlr_foreign_toplevel_handle_v1 *hndl, wl_output *wlOut );
        static void handleState( void *data, zwlr_foreign_toplevel_handle_v1 *hndl, wl_array *state );
        static void handleDone( void *data, zwlr_foreign_toplevel_handle_v1 *hndl );
        static void handleClosed( void *data, zwlr_foreign_toplevel_handle_v1 *hndl );
        static void handleParent( void *data, zwlr_foreign_toplevel_handle_v1 *hndl, zwlr_foreign_toplevel_handle_v1 *parent );

        static const zwlr_foreign_toplevel_handle_v1_listener mWindowHandleListener;

        zwlr_foreign_toplevel_handle_v1 *mObj;

        QString mTitle;
        QString mAppId;

        typedef struct view_state_t {
            bool maximized  = false;
            bool minimized  = false;
            bool activated  = false;
            bool fullscreen = false;
        } ViewState;

        ViewState mViewState;
        ViewState mPendingState;

        wl_output *mOutput    = nullptr;
        WindowHandle *mParent = nullptr;

        /** First time pending */
        bool mFirstPendingTitle  = false;
        bool mFirstPendingAppId  = false;
        bool mFirstPendingState  = false;
        bool mFirstPendingOutput = false;
        bool mFirstPendingParent = false;

        bool mIsSetup = false;

    Q_SIGNALS:
        void titleChanged();
        void appIdChanged();
        void outputEntered( wl_output *wlOut );
        void outputLeft( wl_output *wlOut );
        void stateChanged();
        void closed();
        void parentChanged( WindowHandle *parent );
};
